﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using ExtDirect4DotNet;
using Newtonsoft.Json;

namespace ExtDirect4DotNetSample {
    public class Person {
        public string email { get; set; }

        public string first { get; set; }

        public string id { get; set; }

        public string last { get; set; }
    }

    /// <summary>
    /// A sample Ext.Direct - Action - Class
    /// 
    /// Class is markt as DirectAction via the Direct Action attribute [DirectAction]
    /// 
    /// The Class extends ActionWithSessionState wich makes the curren SessionState in this Action
    /// availible via the Session member.
    /// </summary>
    [DirectAction]
    public class CRUDSampleMethods : DirectActionBase {
        /// <summary>
        /// The C in Crud 
        /// Represents a properitary Logic for creating a Person Object
        /// Adds it to the List in the Session and after that it returns back the Person
        /// 
        /// This Methode has bin marked as a DirectMethod via the DirectMethod Attribute [DirectMethod]
        /// You can configure Different Options for this Methods by setting Properties in the Attribute.
        /// While this Method will get Used in a CRUD Process and some of those Methodes need special Handling
        /// the MethodeType is set To Create.
        /// 
        /// See the MethodType Doc for more information
        /// </summary>
        /// <param name="personToCreate">The Person that should get added to the List in the Session (represents a Record in Extjs)</param>
        /// <returns>The Person that was created</returns>
        [DirectMethod(MethodType = DirectMethodType.Create)]
        public Person create(Person personToCreate) {
            personToCreate.id = generateId();

            getData().Add(personToCreate);

            return personToCreate;
        }

        /// <summary>
        /// The D in cruD 
        /// Represents a properitary Logic for Deleting an existing Person in the List.
        /// 
        /// This Methode is marked as a DirectMethod via the DirectMethod Attribute [DirectMethod]
        /// You can configure Different Options for this Methods by setting Properties in the Attribute.
        /// 
        /// The MethodType is Set to Delete here.
        /// 
        /// An nother Special thing here is the OutputHandling Parameter
        /// This ensures that the Followin Proccess Logic will not rerender the result of this methods
        /// 
        /// Make Sure that the ToString Function of this Function returns Clean JSON if you want to use this Method!
        /// </summary>
        /// <param name="id">Id Of the Person which should get deleted</param>
        /// <returns>just retunrs Success to tell the store that the record was deleted on the Server.</returns>
        [DirectMethod(MethodType = DirectMethodType.Delete, OutputHandling = OutputHandling.JSON)]
        public string destroy(string id) {
            List<Person> persons = getData();
            Person person = persons.Find(t => t.id == id);
            persons.Remove(person);

            return "{\"success\": true}";
        }

        /// <summary>
        /// The R in cRud 
        /// Represents a properitary Logic for Reading.
        /// Will return a List Of Persons Wrapped by a LoadResponse Class
        /// 
        /// This Methode is marked as a DirectMethod via the DirectMethod Attribute [DirectMethod]
        /// You can configure Different Options for this Methods by setting Properties in the Attribute.
        /// 
        /// Special thing here is the ParameterHandling. 
        /// Which is set to AutoResolve her. This means that you can call the Function form the Javascript Side
        /// like this:
        /// 
        /// CRUDSampleMethods.read({sort: 'email', dir:'ASC'})
        /// 
        /// and the DirectMethod Class will try to mapp those Parameters to the Parameters of the .Net Function
        /// 
        /// So this Function will get call as you would call it in .Net the following way.
        /// 
        /// read("email","ASC")
        /// </summary>
        /// <param name="sort">the property to Sort the List of Persons by</param>
        /// <param name="dir">The Direction or "ASC"/"DESC"</param>
        /// <returns>A LoadRespone Object that wraps the Persons</returns>
        [DirectMethod(MethodType = DirectMethodType.Read, ParameterHandling = ParameterHandling.AutoResolve)]
        public LoadResponse read(string sort, string dir, int start, int limit) {
            List<Person> rows = getData();

            switch (sort) {
                case "email":
                    rows.Sort(delegate(Person p1, Person p2) { return p1.email.CompareTo(p2.email); });
                    break;
                case "first":
                    rows.Sort(delegate(Person p1, Person p2) { return p1.first.CompareTo(p2.first); });
                    break;
                case "last":
                default:
                    rows.Sort(delegate(Person p1, Person p2) { return p1.last.CompareTo(p2.last); });
                    break;
            }

            if (dir != "ASC") {
                rows.Reverse();
            }

            if (start != null && limit != null) {
                List<Person> returnList = new List<Person>();
                int i = 0;
                foreach (Person curPers in rows) {
                    if (i >= start && i <= (start + limit)) {
                        returnList.Add(curPers);
                    }
                    i++;
                }
                return new LoadResponse {
                    Results = rows.Count,
                    Rows = returnList
                };
            }

            return new LoadResponse {
                Results = rows.Count,
                Rows = rows
            };
        }

        /// <summary>
        /// just a small function that resets the content of the Session Object
        /// </summary>
        [DirectMethod]
        public void reset() {
            getData(true);
        }

        /// <summary>
        /// The U in crUd 
        /// Represents a properitary Logic for Updating an existing Person in the List.
        /// 
        /// This Methode is marked as a DirectMethod via the DirectMethod Attribute [DirectMethod]
        /// You can configure Different Options for this Methods by setting Properties in the Attribute.
        /// 
        /// The MethodType is Set to Uptdate here.
        /// This means a Special Parameterhandling as well.
        /// The Method will get Called from Extjs in the following Way:
        /// 
        /// update(1,{RECORD});
        /// 
        /// DirectMethodType.Update 
        /// 
        /// Will Pass that into your Function
        /// </summary>
        /// <param name="sort">the property to Sort the List of Persons by</param>
        /// <param name="dir">The Direction or "ASC"/"DESC"</param>
        /// <returns>A LoadRespone Object that wraps the Persons</returns>
        [DirectMethod(MethodType = DirectMethodType.Update)]
        public Person update(string id, Person personWithUpdatedValues) {
            List<Person> persons = getData();
            Person person = persons.Find(t => t.id == id);

            // update logic
            if (personWithUpdatedValues.last != null) {
                person.last = personWithUpdatedValues.last;
            }

            if (personWithUpdatedValues.first != null) {
                person.first = personWithUpdatedValues.first;
            }

            if (personWithUpdatedValues.email != null) {
                person.email = personWithUpdatedValues.email;
            }

            return person;
        }

        /// <summary>
        /// Just a small Id generator jusing the Session to store the highest id
        /// </summary>
        /// <returns>the Id</returns>
        private string generateId() {
            Session["lastId"] = ((int) Session["lastId"]) + 1;
            return Session["lastId"].ToString();
        }

        /// <summary>
        /// Returns a (cached) List of Persons from the Session
        /// </summary>
        /// <returns>The List of Persons</returns>
        private List<Person> getData() {
            return getData(false);
        }

        /// <summary>
        /// Returns a (cached) List of Persons from the Session
        /// </summary>
        /// <param name="fresh">true to clear the Cache</param>
        /// <returns>The List of Persons</returns>
        private List<Person> getData(Boolean fresh) {
            List<Person> personList = (List<Person>) Session["CRUDMethodsData"];
            if (personList == null || fresh) {
                personList = new List<Person>();

                Person p1 = new Person {
                    first = "Martin",
                    last = "Späth",
                    email = "email1@extjs.com",
                    id = "1"
                };
                personList.Add(p1);

                Person p2 = new Person {
                    first = "Heinz",
                    last = "Erhart",
                    email = "email2@extjs.com",
                    id = "2"
                };
                personList.Add(p2);

                Person p3 = new Person {
                    first = "Albert",
                    last = "Einstein",
                    email = "email1@extjs.com",
                    id = "3"
                };
                personList.Add(p3);
                Session["CRUDMethodsData"] = personList;
                Session["lastId"] = 3;
            }

            return personList;
        }
    }

    /// <summary>
    /// Just a small wrapper class for the correct response for a read Action.
    /// </summary>
    public class LoadResponse {
        [JsonProperty(PropertyName = "success")]
        public bool Success = true;

        public LoadResponse() {
        }

        public LoadResponse(DataTable dataTable) {
            DataRow[] arr = new DataRow[dataTable.Rows.Count];
            dataTable.Rows.CopyTo(arr, 0);

            Rows = arr;
            Results = dataTable.Rows.Count;
        }

        /// <summary>
        /// the property which contains the total dataset size (optional)
        /// </summary>
        [JsonProperty(PropertyName = "results")]
        public int Results { get; set; }

        [JsonProperty(PropertyName = "data")]
        public Object Rows { get; set; }
    }
}